#include "../include/allocator.h"
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
// ******************************内存节点操作
int init_memory_pool_node(memory_pool_node_t *node, size_t memory_size) {
  if (!node) {
    return 0;
  }
  /*内存的前面表示所在内存池的地址*/
  node->memory = malloc(sizeof(void *) + memory_size);
  node->next = NULL;
  return 1;
}

memory_pool_node_t *create_memory_pool_node(size_t memory_size) {
  memory_pool_node_t *ret =
      (memory_pool_node_t *)malloc(sizeof(memory_pool_node_t));
  if (!ret) {
    return ret;
  }

  if (!init_memory_pool_node(ret, memory_size)) {
    free(ret);
    return NULL;
  }

  return ret;
}

void close_memory_pool_node(memory_pool_node_t *node) {
  if (!node) {
    return;
  }
  close_memory_pool_node(node->next);
  free(node->memory);
  free(node);
}

void memory_pool_node_push_front(memory_pool_node_t **node,
                                 memory_pool_node_t *new_node) {
  new_node->next = *node;
  *node = new_node;
}

memory_pool_node_t *memory_pool_node_pop_front(memory_pool_node_t **node) {
  memory_pool_node_t *ret = *node;
  if (!ret) {
    return ret;
  }
  *node = (memory_pool_node_t *)ret->next;
  return ret;
}

// ***********************固定大小内存池操作****************************

int init_fixed_size_memory_pool(fixed_size_memory_pool_t *pool,
                                size_t memory_size) {
  if (!pool) {
    return 0;
  }
  pool->memory_size = memory_size;
  pool->node = NULL;
  return 1;
}

void close_fixed_size_memory_pool(fixed_size_memory_pool_t *pool) {
  if (!pool) {
    return;
  }

  close_memory_pool_node(pool->node);
  pool->memory_size = 0;
}

int fixed_size_memory_pool_pre_alloc(fixed_size_memory_pool_t *pool,
                                     size_t size) {
  if (!pool) {
    return 0;
  }

  memory_pool_node_t *new_node = NULL;
  for (int i = 0; i < size; ++i) {
    new_node = create_memory_pool_node(pool->memory_size);
    if (!new_node) {
      return 0;
    }
    memory_pool_node_push_front(&(pool->node), new_node);
  }

  return 1;
}

void *fixed_size_memory_pool_alloc(fixed_size_memory_pool_t *pool) {
  if (!pool) {
    return NULL;
  }

  memory_pool_node_t *ret = memory_pool_node_pop_front(&(pool->node));
  if (!ret) {
    if (!fixed_size_memory_pool_pre_alloc(pool, 1)) {
      return NULL;
    }
    ret = memory_pool_node_pop_front(&(pool->node));
    if (!ret) {
      return NULL;
    }
  }

  ret->next = pool;

  memcpy(ret->memory, &ret, sizeof(void *));

  return (char*)ret->memory + sizeof(void *);
}

void fixed_size_memory_pool_free(void *ptr) {
  memory_pool_node_t **temp = (memory_pool_node_t **)((char*)ptr - sizeof(ptr));
  fixed_size_memory_pool_t *pool = (fixed_size_memory_pool_t *)(*temp)->next;
  memory_pool_node_push_front(&(pool->node), *temp);
}

// ***********************可变内存池操作*******************************

int init_complex_memory_pool(complex_memory_pool_t *pool, size_t block_size,
                             size_t init_line, size_t line_init_size) {
  if (!pool) {
    return 0;
  }

  // 初始化line
  pool->lines = (fixed_size_memory_pool_t *)malloc(
      sizeof(fixed_size_memory_pool_t) * init_line);
  if (!pool->lines) {
    return 0;
  }

  // 初始化每个line
  for (size_t i = 0; i < init_line; ++i) {
    // 初始化line
    if (!init_fixed_size_memory_pool(pool->lines + i, (i + 1) * block_size)) {
      return 0;
    }
    // 预分配当前行内存
    if (!fixed_size_memory_pool_pre_alloc(pool->lines + i, line_init_size)) {
      return 0;
    }
  }

  // 设定其他变量
  pool->block_size = block_size;
  pool->line_size = init_line;
  pool->line_init_size = line_init_size;

  return 1;
}

void close_complex_memory_pool(complex_memory_pool_t *pool) {
  if (!pool) {
    return;
  }
  for (size_t i = 0; i < pool->line_size; ++i) {
    close_fixed_size_memory_pool(pool->lines + i);
  }
  free(pool->lines);
  pool->block_size = 0;
  pool->line_init_size = 0;
  pool->line_size = 0;
}

void *complex_memory_pool_alloc(complex_memory_pool_t *pool, size_t size) {
  if (!pool || size == 0) {
    return NULL;
  }

  int target_index = size / pool->block_size;
  if (size % pool->block_size > 0) {
    target_index += 1;
  }
  target_index -= 1;

  // 如果没有足够大的内存块
  if (target_index >= pool->line_size) {
    pool->lines =
        (fixed_size_memory_pool_t *)realloc(pool->lines, target_index + 1);
    if (!pool->lines) {
      return NULL;
    }

    size_t index = 0;
    for (size_t i = 0; i < target_index + 1 - pool->line_size; ++i) {
      index = pool->line_size + i;
      // 初始化line
      if (!init_fixed_size_memory_pool(pool->lines + index,
                                       (index + 1) * pool->block_size)) {
        return 0;
      }
      // 预分配当前行内存
      if (!fixed_size_memory_pool_pre_alloc(pool->lines + i,
                                            pool->line_init_size)) {
        return 0;
      }
    }
  }

  // 分配内存
  return fixed_size_memory_pool_alloc(pool->lines + target_index);
}

void complex_memory_pool_free(void *ptr) { fixed_size_memory_pool_free(ptr); }

// *********************************不同块大小的内存池*****************************************
complex_memory_pool_t *complex_pools = NULL;

int check_global_pool() {
  if (!complex_pools) {
    complex_pools =
        (complex_memory_pool_t *)calloc(sizeof(complex_memory_pool_t), 7);
    if (!complex_pools) {
      return 0;
    }
  }

  return 1;
}

int memory_pool_level_init(uint8_t level, size_t count) {
  if (level >= 8) {
    return 0;
  }

  if (!check_global_pool()) {
    return 0;
  }

  size_t block_size = 4;
  for (uint8_t i = 0; i < level; ++i) {
    block_size *= 256;
  }

  return init_complex_memory_pool(complex_pools + level, block_size, 255,
                                  count);
}

void *memory_pool_alloc(size_t size) {
  if (!check_global_pool()) {
    return NULL;
  }

  int8_t index = 0;
  size_t block_size = 4;
  do {
    if (block_size * 255 >= size) {
      break;
    }
    index++;
    block_size *= 256;
  } while (1);

  if (complex_pools[index].block_size == 0) {
    if (!init_complex_memory_pool(complex_pools + index, block_size, 255, 0)) {
      return NULL;
    }
  }

  return complex_memory_pool_alloc(complex_pools + index, size);
}

void memory_pool_free(void *ptr) {
  if (!ptr || !check_global_pool()) {
    return;
  }
  fixed_size_memory_pool_free(ptr);
}

void *memory_pool_realloc(void *ptr, size_t osize, size_t size) {
  void *ret = memory_pool_alloc(size);
  if (ret && ptr) {
    memcpy(ret, ptr, osize <= size ? osize : size);
  }
  if (ptr) {
    memory_pool_free(ptr);
  }
  return ret;
}